﻿using maranov.SymlinkManager.ApplicationPrivilege;
using maranov.SymlinkManager.FilesystemLinks;
using maranov.SymlinkManager.FilesystemLinks.PrivilegeCheckProviders;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;

namespace maranov.SymlinkManager.LinkTests
{
    /// <summary>
    /// Tests for HardLink creation and destruction using abstraction.
    /// </summary>
    [TestClass]
    public class HardLinkClassTest
    {
        private void CreateFile(string path)
        {
            if (!File.Exists(path))
            {
                using(var file = File.Create(path))
                {
                    using (var writer = new StreamWriter(file))
                    {
                        writer.WriteLine(path);
                    }
                }
            }
        }

        private void CreateDirectory(string path)
        {
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);
        }

        private void DeleteFile(string path)
        {
            File.Delete(path);
        }

        private void DeleteDirectory(string path)
        {
            Directory.Delete(path);
        }

        [TestInitialize]
        public void CreateFileStructure()
        {
            // Privileges
            ApplicationPrivilegeElevator HardLinkPrivilegeChecker =
                new ApplicationPrivilegeElevator(
                    new HardLinkPrivilegeCheckProvider().PrivilegeCheckRoutines);
            try
            {
                HardLinkPrivilegeChecker.CheckAndElevate(
                    new ApplicationTerminator(delegate()
                        {
                            Environment.Exit(0);
                        })
                        );
            }
            catch (ApplicationElevationException)
            {
                // IsAlreadyAdmin -> error; !IsAlreadyAdmin -> close
                throw;
            }

            // Root
            CreateDirectory(@".\Testing");
            // Folders
            CreateDirectory(@".\Testing\Directory1");
            CreateDirectory(@".\Testing\Directory2");
            // Files
            CreateFile(@".\Testing\RootFile");
            CreateFile(@".\Testing\Directory1\Directory1File");
            CreateFile(@".\Testing\Directory2\Directory2File");
        }

        [TestCleanup]
        public void RemoveFileStructure()
        {
            // Files
            DeleteFile(@".\Testing\RootFile");
            DeleteFile(@".\Testing\Directory1\Directory1File");
            DeleteFile(@".\Testing\Directory2\Directory2File");
            // Folders
            DeleteDirectory(@".\Testing\Directory1");
            DeleteDirectory(@".\Testing\Directory2");
            // Root
            DeleteDirectory(@".\Testing");
        }

        /* Testing
           │   RootFile
           │
           ├───Directory1
           │       Directory1File
           │
           └───Directory2
                   Directory2File
         */

        [TestMethod]
        public void CreateAbsoluteClassHardLink()
        {
            IHardLink absoluteHardLink = new HardLink(
                @".\Testing\AbsoluteHardLink",
                Path.GetFullPath(@".\Testing\Directory1\Directory1File"));
            absoluteHardLink.Create();

            Assert.IsTrue(
                File.Exists(@".\Testing\AbsoluteHardLink")
                );

            absoluteHardLink.Remove();

            Assert.IsFalse(absoluteHardLink.Exists);

            Assert.IsFalse(
                File.Exists(@".\Testing\AbsoluteHardLink")
                );
        }

        [TestMethod]
        public void CreateRelativeClassHardLink()
        {
            IHardLink relativeHardLink = new HardLink(
                @".\Testing\RelativeHardLink",
                @".\Testing\Directory1\Directory1File");
            relativeHardLink.Create();

            Assert.IsTrue(
                File.Exists(@".\Testing\RelativeHardLink")
                );

            // Relativness test
            File.Move(
                @".\Testing\RelativeHardLink",
                @".\Testing\Directory2\RelativeHardLink"
                );

            using (var file = File.Open(@".\Testing\Directory2\RelativeHardLink", FileMode.Open))
            {
                using (var reader = new StreamReader(file))
                {
                    System.Console.WriteLine(reader.ReadToEnd());
                }
            }

            Assert.IsFalse(relativeHardLink.Exists);
            relativeHardLink = new HardLink(
                @".\Testing\Directory2\RelativeHardLink",
                @".\Testing\Directory1\Directory1File");

            relativeHardLink.Remove();

            Assert.IsFalse(relativeHardLink.Exists);
            Assert.IsFalse(
                File.Exists(@".\Testing\Directory2\RelativeHardLink")
                );
        }
    }
}
